/**
 * huize Service Inc
 * All Rights Reserved @2018
 */
package com.huize.ladon.apm.common.util;

import com.huize.ladon.apm.common.constant.CommonConstants;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.math.BigDecimal;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;

import static com.huize.ladon.apm.common.constant.CommonConstants.EXCEPTION_MAX_LENGTH;
import static com.huize.ladon.apm.common.constant.CommonConstants.WILDCARDS;

/**
 * 描述: 各类Utils混合
 *
 * @author tianyuliang
 * @version $Id: MixAllUtils.java, v0.1 2019/3/20
 */
@SuppressWarnings("deprecation")
public class MixAllUtils {

    /**
     * 小数点后的位数
     */
    private static final int scale = 2;

    /**
     * ContextPath分隔符
     */
    private static final String defaultContextPath = "/";

    /**
     * 异常信息分隔符
     */
    private static String SPLIT = ",  ";

    /**
     * 转为Long类型
     *
     * @param value
     * @return
     */
    public static Long parseLong(Object value) {
        return parseLong(value, 0L);
    }

    /**
     * 转为Long类型
     *
     * @param value
     * @param defaultValue
     * @return
     */
    public static Long parseLong(Object value, Long defaultValue) {
        try {
            return Long.parseLong(String.valueOf(value));
        } catch (Exception e) {
            return defaultValue;
        }
    }

    /**
     * 转为Integer类型
     *
     * @param value
     * @return
     */
    public static Integer parseInteger(Object value) {
        return parseInteger(value, 0);
    }

    /**
     * 转为Integer类型
     *
     * @param value
     * @param defaultValue
     * @return
     */
    public static Integer parseInteger(Object value, Integer defaultValue) {
        try {
            return Integer.parseInt(ObjectUtils.toString(value));
        } catch (Exception e) {
            return defaultValue;
        }
    }

    /**
     * 能否转化为Number数字
     *
     * @param value
     * @return
     */
    public static Boolean canParseNumber(Object value) {
        try {
            Long.parseLong(String.valueOf(value));
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 提供精确的小数位四舍五入处理。
     *
     * @param value 需要四舍五入的数字
     * @param scale 小数点后保留几位
     * @return 四舍五入后的结果
     */
    public static float round(float value, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException("the scale must be a positive integer or zero");
        }
        if (Double.isNaN(value) || Float.isNaN(value) || Double.valueOf(value).isInfinite() || Float.valueOf(value).isInfinite()) {
            return 0F;
        }
        try {
            BigDecimal b = new BigDecimal(Double.toString(value));
            BigDecimal one = new BigDecimal("1");
            return b.divide(one, scale, BigDecimal.ROUND_HALF_UP).floatValue();
        } catch (Exception e) {
            e.printStackTrace();
            return 0F;
        }
    }

    /**
     * 格式化Float数据并保留2为小数
     *
     * @param value
     * @return
     */
    public static Float formatFloat(Float value) {
        if (value == null || Float.isNaN(value) || value.isInfinite()) {
            return 0F;
        }
        return round(value, scale);
    }

    /**
     * 格式化Double数据并保留2为小数
     *
     * @param value
     * @return
     */
    public static Float formatFloat(Double value) {
        if (value == null || Double.isNaN(value) || value.isInfinite()) {
            return 0F;
        }
        return round(value.floatValue(), scale);
    }

    /**
     * 两数字相除并把结果转化为百分比
     *
     * @param first
     * @param divisor
     * @return
     */
    public static Float rateDivisor(Integer first, Integer divisor) {
        if (first == null || divisor == null || divisor == 0 || first == 0) {
            return 0F;
        }
        Float value = first * 100.0F / divisor;
        return formatFloat(value);
    }

    /**
     * 两数字相除并把结果转化为百分比
     *
     * @param first
     * @param divisor
     * @return
     */
    public static Float rateDivisor(Long first, Long divisor) {
        if (first == null || divisor == null || divisor == 0 || first == 0) {
            return 0F;
        }
        Float value = first * 100.0F / divisor;
        return formatFloat(value);
    }

    /**
     * 截断exception信息，最长21000字符
     *
     * @param exception
     * @return
     */
    public static String interceptException(String exception) {
        return (isNotEmpty(exception) && exception.length() > EXCEPTION_MAX_LENGTH) ? exception.substring(0, EXCEPTION_MAX_LENGTH - 1) : exception;
    }

    /**
     * 给源字符串开始、结尾都包裹 通配符,例如 product --> %product%，构建mysql模糊匹配参数
     *
     * @param keyword
     * @return
     */
    public static String sqlFieldWrapper(String keyword) {
        return "%" + trimToEmpty(keyword) + "%";
    }

    /**
     * 按逗号默认链接values集合
     *
     * @param values
     * @return
     */
    public static String defaultJoin(Collection<?> values) {
        if (isEmpty(values)) {
            return "";
        }
        return StringUtils.join(values, CommonConstants.DEFAULT_JOIN_SEPARATOR);
    }

    /**
     * 截断链路param信息，最长maxLength字符，包括trace输入/输出参数
     *
     * @param param
     * @param maxLength
     * @return
     */
    public static String interceptTraceParam(String param, int maxLength) {
        return hasCatTraceParam(param, maxLength) ? param.substring(0, maxLength) : param;
    }

    /**
     * 是否需要截断链路param信息，包括trace输入/输出参数
     *
     * @param param
     * @param maxLength
     * @return
     */
    public static boolean hasCatTraceParam(String param, int maxLength) {
        return isNotEmpty(param) && param.length() > maxLength;
    }

    /**
     * 计算数据length
     *
     * @param value
     * @return
     */
    public static int buildLength(String value) {
        return isEmpty(value) ? 0 : value.trim().length();
    }

    /**
     * 给源字符串开始、结尾都包裹 通配符,例如 product --> *product*
     *
     * @param keyword
     * @return
     */
    public static final String wrapWildcards(String keyword) {
        return WILDCARDS + keyword + WILDCARDS;
    }

    /**
     * 给源字符串开始、结尾都包裹 通配符,例如 product --> %product%
     *
     * @param keyword
     * @return
     */
    public static final String wrapFullPath(String keyword) {
        return "%" + keyword + "%";
    }

    /**
     * 给参数内容的首尾包裹() 例如  java.lang.Long,java.lang.String,int   ------> (java.lang.Long, java.lang.String, int)
     *
     * @param paramContent
     * @return
     */
    public static final String wrapParamContent(String paramContent) {
        return String.format("(%s)", paramContent).replace(",", ", ");
    }

    /**
     * 校验是否为操作成功状态码
     *
     * @param statusCode
     * @return 返回true标识操作成功
     */
    public static final boolean isSuccessCode(int statusCode) {
        return CommonConstants.SUCCESS_STATUS_CODE == statusCode;
    }

    /**
     * Boolean类型校验
     *
     * @param value
     * @return
     */
    public static Boolean ok(Boolean value) {
        return value != null && value;
    }

    /**
     * 默认非空集合
     *
     * @param source 集合
     * @return true 非空集合
     */
    public static <T> T firstElement(List<T> source) {
        if (isNotEmpty(source) && source.size() > 0) {
            return source.get(0);
        }
        return null;
    }

    /**
     * 默认非空集合
     *
     * @param source 集合
     * @return true 非空集合
     */
    public static <T> T firstElement(Set<T> source) {
        if (isNotEmpty(source) && source.size() > 0) {
            return firstElement(new ArrayList<>(source));
        }
        return null;
    }

    /**
     * 默认非空集合
     *
     * @param source 集合
     * @return true 非空集合
     */
    public static <T> List<T> defaultList(List<T> source) {
        return isNotEmpty(source) ? source : new ArrayList<>();
    }

    /**
     * 默认非空集合
     *
     * @param source 集合
     * @return true 非空集合
     */
    public static <T> Set<T> defaultSet(Set<T> source) {
        return isNotEmpty(source) ? source : new HashSet<>();
    }

    /**
     * 默认非空Map
     *
     * @param source
     * @return
     */
    public static Map<String, Object> defaultMap(Map<String, Object> source) {
        return isNotEmpty(source) ? source : new HashMap<>();
    }

    /**
     * 判断是否为非空
     *
     * @param collection 集合
     * @return true 集合非空
     */
    public static boolean isNotEmpty(Collection<?> collection) {
        return !isEmpty(collection);
    }

    /**
     * 判断是否为非空
     *
     * @return true 集合为空
     */
    public static boolean isEmpty(Collection<?> collection) {
        return collection == null || collection.size() == 0;
    }

    /**
     * 判断是否为非空
     *
     * @return true 集合为空
     */
    public static boolean isEmpty(String value) {
        return StringUtils.isBlank(value);
    }

    /**
     * 检验为空
     *
     * @param array
     * @return
     */
    public static boolean isEmpty(final Object[] array) {
        return array == null || array.length == 0;
    }

    /**
     * 判断是否为非空
     *
     * @return true 非空
     */
    public static boolean isNotEmpty(Map<?, ?> param) {
        return param != null && param.size() > 0;
    }

    /**
     * 检验不为空
     *
     * @param array
     * @return
     */
    public static boolean isNotEmpty(final Object[] array) {
        return !isEmpty(array);
    }

    /**
     * 判断是否为非空
     *
     * @return true 集合为空
     */
    public static boolean isNotEmpty(String value) {
        return StringUtils.isNotBlank(value);
    }

    /**
     * 移除字符串两端空格
     */
    public static String trimToNull(String value) {
        return StringUtils.trimToNull(value);
    }

    /**
     * 移除字符串两端空格
     */
    public static String trimToEmpty(String value) {
        return StringUtils.trimToEmpty(value);
    }

    /**
     * 移除字符串两端空格，以及“null”字符串
     */
    public static String filterToNull(String value) {
        return (isNotEmpty(value) && value.trim().equalsIgnoreCase("null")) ? null : trimToNull(value);
    }

    /**
     * 判断字符串两端空格，以及“null”字符串
     */
    public static boolean filterNull(String value) {
        return isNotEmpty(value) && !value.trim().equalsIgnoreCase("null");
    }

    /**
     * 移除字符串两端空格，以及“null”字符串
     */
    public static String filterToEmpty(String value) {
        return (isNotEmpty(value) && value.trim().equalsIgnoreCase("null")) ? "" : StringUtils.trimToEmpty(value);
    }

    /**
     * 移除字符串头尾、中间的所有空格
     *
     * @param value
     * @return
     */
    public static String removeAll(String value) {
        return trimToEmpty(value).replaceAll(" ", "");
    }

    /**
     * 判断是否为非空
     *
     * @return true 非空
     */
    public static boolean isNotEmptyMap(Map<?, ?> param) {
        return param != null && param.size() > 0;
    }

    /**
     * 判断是否为非空
     *
     * @return true 集合为空
     */
    public static boolean isEmptyCollection(Collection<?> collection) {
        return collection == null || collection.isEmpty() || collection.size() == 0;
    }

    /**
     * 判断对象所有属性是否为空
     *
     * @param obj          要判断的对象
     * @param ignoreFields 忽略字段
     * @return
     */
    public static boolean isNotNullProperties(Object obj, String... ignoreFields) {
        boolean isNotNull = false;
        try {
            Map<String, Object> map = PropertyUtils.describe(obj);
            map.remove("class");

            if (ignoreFields != null) {
                for (String field : ignoreFields) {
                    map.remove(field);
                }
            }

            Collection<?> collection = map.values();
            for (Object o : collection) {
                if (o != null && StringUtils.isNotBlank(String.valueOf(o).trim())) {
                    isNotNull = true;
                    break;
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return isNotNull;
    }

    /**
     * 获取报错的类、方法
     */
    public static String getTags(Exception ex) {
        if (ex == null) {
            return null;
        }

        StringBuffer buffer = new StringBuffer();
        StackTraceElement[] stList = ex.getStackTrace();
        String clazz = stList[0].getClassName() + SPLIT;            // 哪个类
        String method = stList[0].getMethodName() + SPLIT;          // 哪个方法
        String lineNumber = stList[0].getLineNumber() + SPLIT;      // 在第几行报错
        String exceptionName = ex.getClass().getName() + SPLIT;     // 异常名称

        buffer.append("报错的类：").append(clazz).append("报错的方法：").append(method).append("第几行报错：").append(lineNumber).append("异常类型：").append(exceptionName);
        return buffer.toString();
    }

    /**
     * 构建任意长度的随机字符串
     *
     * @param length
     * @return
     */
    public static String buildArbitraryChar(int length) {
        if (length <= 0 || length >= 300) {
            throw new IllegalArgumentException(String.format("请求参数是length=%s无效的!", length));
        }
        return RandomStringUtils.randomAlphabetic(length);
    }

    /**
     * 从URL地址中解析ContextPath参数
     *
     * @param fullUrl
     * @return
     */
    public static String resolveContextPath(String fullUrl, String suffix) {
        URL url = null;
        try {
            url = new URL(fullUrl.trim());
        } catch (MalformedURLException e) {
            throw new RuntimeException("", e);
        }


        String path = url.getPath();
        path = path.replace("//", defaultContextPath);
        if (path.equalsIgnoreCase(suffix)) {
            return defaultContextPath;
        }

        if (path.endsWith(defaultContextPath)) {
            path = path.substring(0, path.length() - 1);
        }

        if (path.endsWith(suffix)) {
            path = path.substring(0, path.indexOf(suffix));
            return path;
        }
        return defaultContextPath;
    }

    /**
     * 获取test模块的文件路径，该文件要求与clazz处于同一级目录
     *
     * @param clazz    类路径
     * @param fileName 文件名(注意：文件名与class文件需要在一个目录)
     * @return
     */
    public static String buildFileLocalPath(Class<?> clazz, String childPath, String fileName) {
        String resourcePath = Thread.currentThread().getContextClassLoader().getResource("").getPath();
        String parentName = new File(resourcePath).getParentFile().getParent();
        String parentPath = parentName.replace("\\", "/") + childPath;

        String packageName = clazz.getPackage().getName().replace(".", "/");
        String fileLocalPath = parentPath + packageName + "/" + fileName;
        return fileLocalPath;
    }

}
